package TDengineDB

import (
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"
	"sync"
	"time"
)


//文件存储客户端字典
var (
	tDengineClientMap = sync.Map{}
	lock sync.Mutex // 连接锁定防止并发访问
)

//TDengineClient 数据库客户端
type TDengineClient struct {
	user       string        //用户名
	password   string        //密码
	url        string        //数据库地址
	basic      string        //签名
	timeout    time.Duration //超时时间(秒)
	httpClient *http.Client  //客户端
}

//NewTDengineClient 初始化客户端
func NewTDengineClient(ipport string,user string,password string,timeout time.Duration) *TDengineClient {
	client, ok := tDengineClientMap.Load(ipport)
	if ok {
		return client.(*TDengineClient)
	}
	lock.Lock()
	defer lock.Unlock()

	client, ok = tDengineClientMap.Load(ipport)
	if ok {
		return client.(*TDengineClient)
	}
	//请求组织
	basicUrl := strings.Builder{}
	basicUrl.WriteString("http://")
	basicUrl.WriteString(ipport)
	basicUrl.WriteString("/rest/sql")
	basic := base64.StdEncoding.EncodeToString([]byte(fmt.Sprint(user, ":", password)))
	clientNew := &TDengineClient{
		user:     user,
		password: password,
		url:      basicUrl.String(),
		basic:    basic,
		timeout:  timeout,
		httpClient: &http.Client{
			Timeout: timeout,
		},
	}
	tDengineClientMap.Store(ipport, clientNew)
	return clientNew
}


//Execute 执行SQL
//sqlCmd sql语句
func (c *TDengineClient) Execute(sqlCmd string) (*ExecuteResult,error) {
	/*"http://192.168.1.215:6041/rest/sql"*/
	request, err := http.NewRequest("POST", c.url, strings.NewReader(sqlCmd))
	request.Header.Add("Authorization", fmt.Sprint("Basic ", c.basic))
	response, err := c.httpClient.Do(request)
	if err != nil {
		return nil, err
	}
	defer response.Body.Close()
	body, err := ioutil.ReadAll(response.Body)
	if err != nil {
		return nil, errors.New(fmt.Sprint("数据读取异常:", err, "  sql:", sqlCmd))
	}
	result := &ExecuteResult{}
	err = json.Unmarshal(body, result)
	if err != nil {
		return nil, errors.New(fmt.Sprint("json序列化异常:", err))
	}
	//执行异常
	if !result.IsSucc() {
		return result, errors.New(fmt.Sprint("状态：", result.Status, "  错误码:", result.Code, "  错误描述：", result.Desc, " sql:", sqlCmd))
	}
	return result, nil
}
